package com.base;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import com.utils.Logger;
import com.utils.StringTool;

public class DBPoolUnContext {
	private static Logger logger = new Logger(DBPoolUnContext.class.getName());
	private static Map<String, LinkedList<Connection>> poolMap = new Hashtable<String, LinkedList<Connection>>();
	public final static int MAX_CONNECTIONS = 10;
	public final static int INI_CONNECTIONS = 2;

	static { // Make connections
		buildPool();
		System.out.println("AutoRefresh="+Config.getStringProperty("AutoRefresh", "0", false));
	}

	public static void buildPool() {
		synchronized (poolMap) {
			String poolName = Config.getStringProperty("poolName", "", false);
			if (StringTool.isEmptyOrNul(poolName))
				return;
			String[] arrPoolName = poolName.split(",");
			for (int i = 0; i < arrPoolName.length; i++) {
				LinkedList<Connection> pool = new LinkedList<Connection>();
				String poolNameItem = arrPoolName[i];
				int numConnection = Config.getIntProperty(poolNameItem
						+ "_connection", 2);
				logger.log("Establishing " + poolNameItem + " pool, "
						+ numConnection + " connections...");
				Connection conn = null;
				release(poolNameItem);
				for (int j = 0; j < numConnection; j++) {
					try {
						conn = makeDBConnection(poolNameItem);
					} catch (SQLException ex) {
						logger.error(ex.getMessage());
						logger.error("Hix,Khong noi dc voi database roi !");
					}
					if (conn != null) {
						pool.addLast(conn);
					}
				}
				logger.log("Number of connection: " + pool.size());
				poolMap.put(poolNameItem, pool);
			}
		}
	}

	public static Connection getConnection(String poolName) {
		Connection conn = null;
		synchronized (poolMap) {
			LinkedList<Connection> pool = poolMap.get(poolName);
			if (pool == null)
				pool = new LinkedList<Connection>();
			try {
				synchronized (pool) {
					conn = (java.sql.Connection) pool.removeFirst();
				}
				if (conn == null || conn.isClosed()) {
					conn = makeDBConnection(poolName);
				}
				try {
					conn.setAutoCommit(true);
				} catch (Exception ex) {
				}

			} catch (Exception e) {
				logger.error("Method getConnection(): Error executing >>>"
						+ e.toString());
				try {
					conn = makeDBConnection(poolName);
					conn.setAutoCommit(true);
				} catch (SQLException e1) {
				}
			}
		}
		return conn;
	}

	public static void putConnection(String poolName, java.sql.Connection conn) {
		synchronized (poolMap) {
			LinkedList<Connection> pool = poolMap.get(poolName);
			if (pool == null)
				pool = new LinkedList<Connection>();
			try { // Ignore closed connection
				if (conn == null || conn.isClosed()) {
					logger
							.log("putConnection: conn is null or closed: "
									+ conn);
					return;
				}

				if (pool.size() >= MAX_CONNECTIONS) {
					conn.close();
					return;
				}
			} catch (SQLException ex) {
			}
			try {
				conn.setAutoCommit(true);
			} catch (SQLException e) {
			}
			synchronized (pool) {
				pool.addLast(conn);
				pool.notify();
			}

			poolMap.put(poolName, pool);
		}
	}

	// Remove and close all connections in pool
	public static void release(String poolName) {
		logger.log("Closing connections in " + poolName + " pool...");
		synchronized (poolMap) {
			LinkedList<Connection> pool = poolMap.get(poolName);
			if (pool == null)
				return;
			synchronized (pool) {
				for (Iterator<Connection> it = pool.iterator(); it.hasNext();) {
					Connection conn = it.next();
					try {
						conn.close();
					} catch (SQLException e) {
						logger
								.error("release: Cannot close connection! (maybe closed?)");
					}
				}
				pool.clear();
			}
			poolMap.remove(poolName);
			logger.log("Release connection OK");
		}
	}

	public static int size(String poolName) {
		synchronized (poolMap) {
			LinkedList<Connection> pool = poolMap.get(poolName);
			if (pool == null)
				return 0;
			synchronized (pool) {
				return pool.size();
			}
		}
	}

	public static boolean isEmpty(String poolName) {
		LinkedList<Connection> pool = poolMap.get(poolName);
		if (pool == null)
			return true;
		synchronized (pool) {
			return pool.isEmpty();
		}
	}

	public static boolean isClosed(String poolName) {
		boolean closed = false;
		LinkedList<Connection> pool = poolMap.get(poolName);
		if (pool == null)
			return true;
		synchronized (pool) {
			for (Iterator<Connection> it = pool.iterator(); it.hasNext();) {
				try {
					Connection conn = it.next();
					if (conn == null || conn.isClosed()) {
						closed = true;
					}
				} catch (SQLException e) {
					closed = true;
				}
			}
		}
		return closed;
	}

	// --------------------------------------------------------------------------
	public static Connection makeDBConnection(String poolName)
			throws SQLException {
		Connection conn = null;
		try {
			String dbType = Config.getStringProperty(poolName + "_type", "",
					false);
			Class.forName(Config.getStringProperty(poolName + "_driverClass",
					"", false));
			if ("MSSQL".equalsIgnoreCase(dbType)) {
				// if database is SQL Server
				String url = Config.getStringProperty(
						poolName + "_driverURL", "", false);
				url += ";UID="
						+ Config.getStringProperty(poolName + "_dbuser", "",
								false)
						+ ";"
						+ "PWD="
						+ Config.getStringProperty(poolName + "_dbpassword",
								"", false)
						+ ";"
						+ "DATABASE="
						+ Config.getStringProperty(poolName + "_dbname", "",
								false);
				conn = DriverManager.getConnection(url);
			} else {
				// System.out.println("URL
				// ="+DBConfig.getStringProperty(poolName + "_driverURL", "",
				// false));
				// System.out.println("User="+DBConfig.getStringProperty(poolName
				// + "_dbuser", "", false));
				conn = DriverManager.getConnection(Config.getStringProperty(
						poolName + "_driverURL", "", false), Config
						.getStringProperty(poolName + "_dbuser", "", false),
						Config.getStringProperty(poolName + "_dbpassword",
								"", false));
			}
		} catch (ClassNotFoundException ex) {
			throw new SQLException(ex.toString());
		}
		return conn;
	}

	public static void releaseConnection(String poolName, Connection conn,
			PreparedStatement preStmt) {
		// try {if (conn != null) {conn.close(); } } catch (SQLException e) { }
		putConnection(poolName, conn);
		try {
			if (preStmt != null) {
				preStmt.close();
			}
		} catch (SQLException e) {
		}
	}

	public static void releaseConnection(String poolName, Connection conn,
			PreparedStatement preStmt, ResultSet rs) {
		releaseConnection(poolName, conn, preStmt);
		try {
			if (rs != null) {
				rs.close();
			}
		} catch (SQLException e) {
		}
	}

	public static void releaseConnection(String poolName, Connection conn,
			PreparedStatement preStmt, Statement stmt, ResultSet rs) {
		releaseConnection(poolName, conn, preStmt, rs);
		try {
			if (stmt != null) {
				stmt.close();
			}
		} catch (SQLException e) {
		}
	}

	public static void load() {
	}

	public static void main(String args[]) {
		System.out.println(getConnection("w10h"));
	}
}
